package luke.ui.components;

import javax.swing.*;
import java.awt.*;

import java.awt.geom.Line2D;
import java.awt.geom.Path2D;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.File;

// 导入PlaybackStateManager
import luke.core.utils.PlaybackStateManager;
import luke.audio.analyzer.UniversalAudioDecoder;
import luke.audio.analyzer.UniversalAudioDecoder.AudioData;
import luke.core.utils.LanguageManager; // 新增：导入LanguageManager

/**
 * 实时波形显示面板
 * 实现播放时实时往左移动的波形图，显示当前播放位置的波形
 */
public class RealtimeWaveformPanel extends JPanel implements PlaybackStateManager.PlaybackStateListener, PlaybackStateManager.MetadataListener, PlaybackStateManager.BeatEnableListener, PlaybackStateManager.BeatLinesVisibilityListener {
    // 音频数据
    private float[] audioData;
    private float[] leftChannelData;  // 左声道数据
    private float[] rightChannelData; // 右声道数据
    private float[] mergedChannelData; // 合并声道数据
    private int sampleRate;
    private int channels;

    // BPM和偏移量信息
    private double bpm = 0.0;
    private int offset = 0;
    
    // 实时播放相关
    private boolean isPlaying = false;
    
    // 鼓点闪烁相关
    private List<Integer> activeBeats = new ArrayList<>(); // 当前应该闪烁的鼓点
    private Map<Integer, Long> beatFlashTimes = new HashMap<>(); // 每个鼓点的闪烁开始时间
    private final Object beatsLock = new Object(); // 用于同步访问activeBeats和beatFlashTimes的锁
    private static final long BEAT_FLASH_DURATION = 300; // 闪烁持续时间300ms

    
    // 波形显示参数
    private static final int WAVEFORM_HEIGHT = 200; // 波形显示区域高度
    
    // 颜色配置
    private Color waveformColor = new Color(27, 121, 148); // #1b7994 - 蓝色波形（根据用户偏好修改）
    private Color beatMarkerColor = new Color(27, 121, 148); // #1b7994 - 蓝色鼓点线
    private Color activeBeatColor = Color.WHITE; // 激活的鼓点颜色（闪烁效果）
    private Color backgroundColor = new Color(50, 50, 50); // 深灰色背景色
    private Color playheadColor = Color.RED; // 播放头颜色
    private Color gridColor = new Color(60, 60, 60);
    
    // 波形振幅缩放因子
    private static final float WAVEFORM_AMPLITUDE_SCALE = 1.0f; // 增加振幅缩放因子
    
    // 添加PlaybackStateManager引用
    private PlaybackStateManager playbackStateManager;
    
    // 添加鼓点启用状态字段
    private boolean beatEnabled = false;
    
    // 添加鼓点线条可见性字段
    private boolean beatLinesVisible = true;
    
    // 添加对PlayController的引用
    private luke.core.controller.PlayController playController;
    
    // 当前播放位置（由onPositionChanged提供）
    private long currentPlaybackPosition = 0;
    
    // 添加LanguageManager引用
    private LanguageManager languageManager;
    
    public RealtimeWaveformPanel() {
        // 初始化LanguageManager
        this.languageManager = LanguageManager.getInstance();
        
        // 初始化PlaybackStateManager并注册为监听器
        this.playbackStateManager = PlaybackStateManager.getInstance();
        this.playbackStateManager.addListener((PlaybackStateManager.PlaybackStateListener) this);
        this.playbackStateManager.addListener((PlaybackStateManager.MetadataListener) this);
        this.playbackStateManager.addListener((PlaybackStateManager.BeatEnableListener) this);
        this.playbackStateManager.addListener((PlaybackStateManager.BeatLinesVisibilityListener) this);
        
        setPreferredSize(new Dimension(800, WAVEFORM_HEIGHT));
        setBackground(backgroundColor);
        
        // 移除了playTimer的初始化，不再使用独立的Timer
    }
    

    
    /**
     * 分离左右声道数据
     * 
     * @param interleavedData 交叉存储的PCM数据
     */
    private void separateChannels(float[] interleavedData) {
        int singleChannelLength = interleavedData.length / 2;
        leftChannelData = new float[singleChannelLength];
        rightChannelData = new float[singleChannelLength];
        
        for (int i = 0; i < singleChannelLength; i++) {
            leftChannelData[i] = interleavedData[i * 2];     // 左声道（偶数索引）
            rightChannelData[i] = interleavedData[i * 2 + 1]; // 右声道（奇数索引）
        }
    }
    
    /**
     * 合并左右声道数据
     */
    private void mergeChannels() {
        if (leftChannelData == null || rightChannelData == null) {
            return;
        }
        
        int length = Math.min(leftChannelData.length, rightChannelData.length);
        mergedChannelData = new float[length];
        
        for (int i = 0; i < length; i++) {
            // 简单平均合并左右声道
            mergedChannelData[i] = (leftChannelData[i] + rightChannelData[i]) / 2.0f;
        }
    }

    
    /**
     * 根据BPM和偏移量计算鼓点位置
     */
    private List<Integer> calculateBeatPositions() {
        List<Integer> beatPositions = new ArrayList<>();
        
        if (audioData == null || sampleRate <= 0 || bpm <= 0) {
            return beatPositions;
        }
        
        // 计算音频总时长（毫秒）
        int durationMs = (int) ((long) audioData.length * 1000 / (sampleRate * channels));
        
        // 如果有播放控制器，使用它来计算鼓点位置
        if (playController != null) {
            return playController.getBeatPositions(durationMs);
        }
        
        // 否则使用本地计算（作为降级方案）
        // 根据BPM和偏移量生成鼓点
        double beatIntervalMs = 60000.0 / bpm;
        double currentTime = offset;
        
        while (currentTime < durationMs) {
            if (currentTime >= 0) { // 只添加非负时间的鼓点
                beatPositions.add((int) Math.round(currentTime));
            }
            currentTime += beatIntervalMs;
        }
        
        return beatPositions;
    }
    
    /**
     * 更新当前应该闪烁的鼓点
     */
    private void updateActiveBeats() {
        if (bpm <= 0) {
            return;
        }
        
        // 使用同步块确保线程安全
        synchronized (beatsLock) {
            long currentTime = currentPlaybackPosition;
            
            // 清除过期的激活鼓点 - 使用更安全的方式避免并发修改异常
            // 创建新的列表来存储未过期的鼓点，避免在迭代过程中修改列表
            List<Integer> remainingBeats = new ArrayList<>();
            Map<Integer, Long> remainingFlashTimes = new HashMap<>();
            
            for (Integer beatTime : activeBeats) {
                // 确保不会发生整数溢出
                long beatTimeLong = beatTime.longValue();
                if (currentTime - beatTimeLong <= BEAT_FLASH_DURATION) {
                    remainingBeats.add(beatTime);
                    Long flashTime = beatFlashTimes.get(beatTime);
                    if (flashTime != null) {
                        remainingFlashTimes.put(beatTime, flashTime);
                    }
                }
            }
            
            // 更新列表
            activeBeats.clear();
            activeBeats.addAll(remainingBeats);
            beatFlashTimes.clear();
            beatFlashTimes.putAll(remainingFlashTimes);
            
            // 检查是否有新的鼓点需要激活（在当前时间附近）
            int tolerance = 50; // 时间容差50毫秒
            
            // 计算当前的鼓点位置
            List<Integer> beatPositions = calculateBeatPositions();
            
            // 创建新的列表来存储需要添加的鼓点，避免在迭代过程中修改列表
            List<Integer> newBeats = new ArrayList<>();
            Map<Integer, Long> newFlashTimes = new HashMap<>();
            
            for (int beatTime : beatPositions) {
                // 如果鼓点时间接近当前播放时间，激活它
                if (Math.abs((long)beatTime - currentTime) <= tolerance) {
                    if (!activeBeats.contains(beatTime)) {
                        newBeats.add(beatTime);
                        newFlashTimes.put(beatTime, System.currentTimeMillis());
                    }
                }
            }
            
            // 添加新的鼓点
            activeBeats.addAll(newBeats);
            beatFlashTimes.putAll(newFlashTimes);
        }
    }
    

    
    // 实现PlaybackStateListener接口的方法
    @Override
    public void onPlaybackStateChanged(boolean isPlaying) {
        this.isPlaying = isPlaying;
        // 确保重绘
        repaint();
    }
    
    @Override
    public void onPositionChanged(long position) {
        // 位置变化时更新当前播放位置
        currentPlaybackPosition = position; // 位置已经是毫秒单位，无需转换
        // 更新激活的鼓点
        updateActiveBeats();
        // 强制重绘整个面板
        repaint();
    }
    
    @Override
    public void onDurationChanged(long duration) {
        // 重新绘制面板
        repaint();
    }
    
    @Override
    public void onFileChanged(File file) {
        // 文件变化时的处理逻辑
        if (file == null) {
            // 清除当前的音频数据和相关状态
            this.audioData = null;
            this.leftChannelData = null;
            this.rightChannelData = null;
            this.mergedChannelData = null;
            this.sampleRate = 0;
            this.channels = 0;
            this.bpm = 0.0;
            this.offset = 0;

            
            // 重置播放位置
            this.currentPlaybackPosition = 0;
            
            // 清除鼓点相关状态 - 使用同步块确保线程安全
            synchronized (beatsLock) {
                this.activeBeats.clear();
                this.beatFlashTimes.clear();
            }
            
            // 重新绘制面板
            repaint();
            return;
        }
        
        // 在后台线程中解码音频文件
        new Thread(() -> {
            try {
                // 使用UniversalAudioDecoder解码音频文件
                UniversalAudioDecoder decoder = new UniversalAudioDecoder();
                AudioData audioDataObj = decoder.decodeAudioFile(file);
                
                // 在EDT中更新UI
                SwingUtilities.invokeLater(() -> {
                    // 更新音频数据
                    this.audioData = audioDataObj.data;
                    this.sampleRate = audioDataObj.sampleRate;
                    this.channels = audioDataObj.channels;
                    
                    // 预处理音频数据，分离左右声道并生成合并声道
                    if (channels == 2 && this.audioData != null) {
                        separateChannels(this.audioData);
                        mergeChannels(); // 生成合并声道数据
                    } else {
                        // 单声道或空数据情况
                        this.leftChannelData = this.audioData;
                        this.rightChannelData = null;
                        this.mergedChannelData = this.audioData; // 直接使用单声道数据作为合并数据
                    }

                    // 重置播放位置
                    this.currentPlaybackPosition = 0;
                    
                    // 清除鼓点相关状态 - 使用同步块确保线程安全
                    synchronized (beatsLock) {
                        this.activeBeats.clear();
                        this.beatFlashTimes.clear();
                    }
                    
                    // 重新绘制面板
                    repaint();
                });
            } catch (Exception e) {
                System.err.println("解码音频文件时出错: " + e.getMessage());
                e.printStackTrace();
                
                // 在EDT中更新UI
                SwingUtilities.invokeLater(() -> {
                    // 清除当前的音频数据和相关状态
                    this.audioData = null;
                    this.leftChannelData = null;
                    this.rightChannelData = null;
                    this.mergedChannelData = null;
                    this.sampleRate = 0;
                    this.channels = 0;
                    this.bpm = 0.0;
                    this.offset = 0;

                    
                    // 重置播放位置
                    this.currentPlaybackPosition = 0;
                    
                    // 清除鼓点相关状态 - 使用同步块确保线程安全
                    synchronized (beatsLock) {
                        this.activeBeats.clear();
                        this.beatFlashTimes.clear();
                    }
                    
                    // 重新绘制面板
                    repaint();
                });
            }
        }).start();
    }
    
    // 实现MetadataListener接口的方法
    @Override
    public void onBpmChanged(double bpm) {
        // BPM变化时更新BPM信息
        if (this.bpm != bpm) {
            this.bpm = bpm;

            repaint();
        }
    }
    
    @Override
    public void onBeatOffsetChanged(int offset) {
        // 节拍偏移变化时更新偏移信息
        if (this.offset != offset) {
            this.offset = offset;

            repaint();
        }
    }
    
    // 实现BeatEnableListener接口的方法
    @Override
    public void onBeatEnabledChanged(boolean enabled) {
        // 鼓点启用状态变化时的处理逻辑
        this.beatEnabled = enabled;
        // 重新绘制以显示或隐藏鼓点
        repaint();
    }
    
    // 实现BeatLinesVisibilityListener接口的方法
    @Override
    public void onBeatLinesVisibilityChanged(boolean visible) {
        // 鼓点线条可见性变化时的处理逻辑
        this.beatLinesVisible = visible;
        // 重新绘制以显示或隐藏鼓点线条
        repaint();
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        
        // 设置抗锯齿
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
        
        int width = getWidth();
        int height = getHeight();
        
        // 绘制背景
        g2d.setColor(backgroundColor);
        g2d.fillRect(0, 0, width, height);
        
        // 如果没有音频数据，显示提示信息
        if (audioData == null || audioData.length == 0) {
            drawNoDataMessage(g2d, width, height);
            g2d.dispose();
            return;
        }
        
        // 绘制波形和鼓点
        drawWaveformAndBeats(g2d, width, height);
        
        // 绘制播放头（在中央）
        drawPlayhead(g2d, width, height);
        
        g2d.dispose();
    }
    
    /**
     * 绘制无数据提示信息
     */
    private void drawNoDataMessage(Graphics2D g2d, int width, int height) {
        g2d.setColor(Color.WHITE);
        g2d.setFont(new Font("SansSerif", Font.PLAIN, 14));
        String message = languageManager.getString("waveform.no.data.message");
        FontMetrics fm = g2d.getFontMetrics();
        int x = (width - fm.stringWidth(message)) / 2;
        int y = (height + fm.getAscent()) / 2;
        g2d.drawString(message, x, y);
    }
    
    /**
     * 绘制波形和鼓点
     */
    private void drawWaveformAndBeats(Graphics2D g2d, int width, int height) {
        if (audioData == null || audioData.length == 0) {
            return;
        }
        // 获取当前播放位置
        long currentPositionMs = currentPlaybackPosition;

        // 使用固定的时间窗口计算，确保显示范围稳定
        int displayDurationMs = 20000; // 显示20秒的波形
        
        // 实现摄像机跟随角色的效果：
        // 前10秒：红线从左向右移动到屏幕中央，波形不动 [0, 20000]
        // 10秒后：红线固定在屏幕中央，波形开始向左移动 [current-10000, current+10000]
        long viewStartTime, viewEndTime;
        
        if (currentPositionMs < 10000) {
            // 前10秒，视图固定
            viewStartTime = 0;
            viewEndTime = displayDurationMs;
        } else {
            // 10秒后，视图跟随当前位置
            viewStartTime = currentPositionMs - displayDurationMs/2;
            viewEndTime = currentPositionMs + displayDurationMs/2;
        }
        
        // 确保视图时间窗口不超出音频范围
        if (sampleRate > 0 && channels > 0) {
            long durationMs = (long) audioData.length * 1000 / (sampleRate * channels);
            if (viewEndTime > durationMs) {
                viewEndTime = durationMs;
                viewStartTime = Math.max(0, durationMs - displayDurationMs);
            }
            // 确保视图开始时间不小于0
            viewStartTime = Math.max(0, viewStartTime);
        }
        
        // 绘制波形
        drawWaveform(g2d, width, height, viewStartTime, viewEndTime);
        
        // 绘制鼓点
        drawBeatMarkers(g2d, width, height, viewStartTime, viewEndTime);
    }
    
    /**
     * 绘制波形
     */
    private void drawWaveform(Graphics2D g2d, int width, int height, long viewStartTime, long viewEndTime) {
        // 只绘制合并声道波形
        drawMergedWaveform(g2d, width, height, viewStartTime, viewEndTime);
    }
    
    /**
     * 绘制合并声道波形
     */
    private void drawMergedWaveform(Graphics2D g2d, int width, int height, long viewStartTime, long viewEndTime) {
        // 使用合并后的单声道数据
        float[] channelData = mergedChannelData != null ? mergedChannelData : audioData;
        
        if (channelData == null || channelData.length == 0) {
            return;
        }
        
        g2d.setColor(waveformColor);
        g2d.setStroke(new BasicStroke(1.5f));
        
        int centerY = height / 2;
        // 使用固定的振幅缩放因子，避免每次绘制时重新计算导致的闪动
        int halfHeight = (int) ((height / 2 - 20) * WAVEFORM_AMPLITUDE_SCALE);
        
        // 计算时间范围
        long timeRange = viewEndTime - viewStartTime;
        // 确保时间范围不为0，避免除零错误
        if (timeRange <= 0) {
            return;
        }
        
        // 使用Path2D绘制连续的波形线
        Path2D waveformPath = new Path2D.Double();
        boolean firstPoint = true;
        
        for (int x = 0; x < width; x++) {
            // 计算当前像素对应的时间范围
            long pixelStartTime = viewStartTime + (long) (x * timeRange / (double) width);
            long pixelEndTime = viewStartTime + (long) ((x + 1) * timeRange / (double) width);
            
            // 计算对应的音频样本索引范围
            int startSampleIndex = (int) (pixelStartTime * sampleRate / 1000);
            int endSampleIndex = (int) (pixelEndTime * sampleRate / 1000);
            
            // 确保索引在有效范围内
            startSampleIndex = Math.max(0, Math.min(channelData.length - 1, startSampleIndex));
            endSampleIndex = Math.max(0, Math.min(channelData.length - 1, endSampleIndex));
            
            // 确保起始索引不大于结束索引
            if (startSampleIndex > endSampleIndex) {
                int temp = startSampleIndex;
                startSampleIndex = endSampleIndex;
                endSampleIndex = temp;
            }
            
            // 在该像素范围内查找最大和最小振幅值
            float minAmplitude = Float.MAX_VALUE;
            float maxAmplitude = Float.MIN_VALUE;
            
            for (int i = startSampleIndex; i <= endSampleIndex; i++) {
                float amplitude = channelData[i];
                // 确保振幅在[-1, 1]范围内
                amplitude = Math.max(-1.0f, Math.min(1.0f, amplitude));
                minAmplitude = Math.min(minAmplitude, amplitude);
                maxAmplitude = Math.max(maxAmplitude, amplitude);
            }
            
            // 如果找到了有效数据
            if (minAmplitude != Float.MAX_VALUE && maxAmplitude != Float.MIN_VALUE) {
                // 绘制最大值和最小值之间的连线
                int minY = centerY - (int) (maxAmplitude * halfHeight);
                int maxY = centerY - (int) (minAmplitude * halfHeight);
                
                // 确保坐标在有效范围内
                minY = Math.max(0, Math.min(height, minY));
                maxY = Math.max(0, Math.min(height, maxY));
                
                // 绘制连线
                if (firstPoint) {
                    waveformPath.moveTo(x, minY);
                    waveformPath.lineTo(x, maxY);
                    firstPoint = false;
                } else {
                    waveformPath.lineTo(x, minY);
                    waveformPath.lineTo(x, maxY);
                }
            }
        }
        
        g2d.draw(waveformPath);
    }
    

    /**
     * 绘制鼓点标记
     */
    private void drawBeatMarkers(Graphics2D g2d, int width, int height, long viewStartTime, long viewEndTime) {
        // 只有在鼓点启用且鼓点线条可见时才绘制鼓点标记
        if (!beatEnabled || !beatLinesVisible || bpm <= 0 || sampleRate <= 0) {
            return;
        }
        
        // 计算时间范围
        long timeRange = viewEndTime - viewStartTime;
        // 确保时间范围不为0，避免除零错误
        if (timeRange <= 0) {
            return;
        }
        
        // 获取当前时间用于计算闪烁效果
        long currentTime = System.currentTimeMillis();
        
        // 计算当前的鼓点位置
        List<Integer> beatPositions = calculateBeatPositions();
        
        // 使用同步块确保线程安全
        synchronized (beatsLock) {
            for (int beatTime : beatPositions) {
                if (beatTime >= viewStartTime && beatTime <= viewEndTime) {
                    // 计算鼓点在屏幕上的位置
                    long timeDiff = beatTime - viewStartTime;
                    int x = (int) (timeDiff * width / timeRange);
                    
                    // 检查是否是激活的鼓点并计算闪烁效果
                    boolean isActive = activeBeats.contains(beatTime);
                    float strokeWidth = 1.0f; // 默认线宽改为1.0f，更细一些
                    Color beatColor = beatMarkerColor; // 默认颜色
                    
                    if (isActive) {
                        // 获取该鼓点的闪烁开始时间
                        Long flashStartTime = beatFlashTimes.get(beatTime);
                        if (flashStartTime != null) {
                            // 计算闪烁效果：根据激活时间计算透明度和线宽
                            long timeSinceActivation = currentTime - flashStartTime;
                            if (timeSinceActivation < BEAT_FLASH_DURATION) {
                                // 计算闪烁因子 (0.0 到 1.0)
                                float flashFactor = 1.0f - (float) timeSinceActivation / BEAT_FLASH_DURATION;
                                
                                // 线宽从6.0f渐变到1.0f（增加最大线宽使效果更明显）
                                strokeWidth = 1.0f + 5.0f * flashFactor;
                                
                                // 颜色从白色渐变到默认颜色（通过调整透明度实现渐变效果）
                                int alpha = (int) (255 * flashFactor);
                                beatColor = new Color(activeBeatColor.getRed(), activeBeatColor.getGreen(), activeBeatColor.getBlue(), Math.max(alpha, 50));
                            } else {
                                // 闪烁时间结束后使用默认设置
                                strokeWidth = 1.0f;
                                beatColor = beatMarkerColor;
                            }
                        }
                    }
                    
                    g2d.setColor(beatColor);
                    g2d.setStroke(new BasicStroke(strokeWidth));
                    
                    // 绘制垂直线
                    g2d.draw(new Line2D.Double(x, 0, x, height));
                    
                    // 移除了三角形标记的绘制，使界面更简洁
                }
            }
        }
    }
    
    /**
     * 绘制播放头
     */
    private void drawPlayhead(Graphics2D g2d, int width, int height) {
        g2d.setColor(playheadColor);
        g2d.setStroke(new BasicStroke(2.0f)); // 适中的红线
        
        // 计算播放头在屏幕上的位置
        long currentPositionMs = currentPlaybackPosition;
        
        // 使用与drawWaveformAndBeats相同的时间窗口计算逻辑
        int displayDurationMs = 20000; // 显示20秒的波形
        
        // 实现摄像机跟随角色的效果：
        // 前10秒：红线从左向右移动到屏幕中央，波形不动 [0, 20000]
        // 10秒后：红线固定在屏幕中央，波形开始向左移动 [current-10000, current+10000]
        long viewStartTime, viewEndTime;
        
        if (currentPositionMs < 10000) {
            // 前10秒，视图固定
            viewStartTime = 0;
            viewEndTime = displayDurationMs;
        } else {
            // 10秒后，视图跟随当前位置
            viewStartTime = currentPositionMs - displayDurationMs/2;
            viewEndTime = currentPositionMs + displayDurationMs/2;
        }
        
        // 确保视图时间窗口不超出音频范围
        if (sampleRate > 0 && channels > 0) {
            long durationMs = (long) audioData.length * 1000 / (sampleRate * channels);
            if (viewEndTime > durationMs) {
                viewEndTime = durationMs;
                viewStartTime = Math.max(0, durationMs - displayDurationMs);
            }
            // 确保视图开始时间不小于0
            viewStartTime = Math.max(0, viewStartTime);
        }
        
        // 计算播放头在屏幕上的位置
        if (currentPositionMs < viewStartTime) {
            // 播放头在视图左侧
            g2d.draw(new Line2D.Double(0, 0, 0, height));
        } else if (currentPositionMs > viewEndTime) {
            // 播放头在视图右侧
            g2d.draw(new Line2D.Double(width, 0, width, height));
        } else {
            // 播放头在视图内
            long timeDiff = currentPositionMs - viewStartTime;
            long timeRange = viewEndTime - viewStartTime;
            // 确保时间范围不为0，避免除零错误
            if (timeRange > 0) {
                int x = (int) (timeDiff * width / timeRange);
                g2d.draw(new Line2D.Double(x, 0, x, height));
            }
        }
    }
}